home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
amok_lha
/
amok77.lha
/
Lichtorgel
/
Lichtorgel.mod
< prev
next >
Wrap
Text File
|
1993-08-15
|
12KB
|
452 lines
(*---------------------------------------------------------------------------
:Program. Lichtorgel.mod
:Contents. Simulation einer 8-Kanal Lichtorgel
:Author. Christian Stiens
:Address. Heustiege 2, W-4710 Lüdinghausen
:Copyright. Freeware, All Rights Reserved, © 1992 by cs-soft
:Language. Oberon-2
:Translator. Amiga Oberon V2.42d (inofficial ß-version)
:History. V1.0, 07-Sep-92
:Imports. Menu (AMOK #59), FFT (AMOK #68)
---------------------------------------------------------------------------*)
(* $StackChk- weil wenig lokale Variablen und keine Rekursion *)
MODULE Lichtorgel;
IMPORT
au := Audio,
e := Exec,
es := ExecSupport,
FFT,
g := Graphics,
hw := Hardware,
I := Intuition,
Misc,
m := Menu,
rq := Requests,
ol := OberonLib,
sys:= SYSTEM;
CONST
ver = "\o$VER: lichtorgel 1.0 (7.9.92)\n\r";
oom = "Speichermangel";
CONST
n = 16; (* 16 Punkt FFT *)
VAR
nw : I.NewWindow;
win : I.WindowPtr;
scr : I.ScreenPtr;
menu : I.MenuPtr;
ioa : au.IOAudioPtr;
mes : I.IntuiMessage;
pp,pb : e.APTR;
chan : SHORTINT;
col : ARRAY 16 OF INTEGER;
i,w,x,y : INTEGER;
shift : INTEGER;
rp : g.RastPortPtr;
vp : g.ViewPortPtr;
hold : ARRAY 8 OF INTEGER;
xreal,
ximag : ARRAY n OF INTEGER;
sintab ["_sintab_1024x16"] : ARRAY 1024 OF INTEGER;
(*---------------------------------------------------------------------*)
TYPE InitProc = PROCEDURE(ioReq: e.MessagePtr);
PROCEDURE OpenDev (name : ARRAY OF CHAR;
unit : LONGINT;
flags : LONGSET;
ioSize : INTEGER;
ioInit : InitProc): e.MessagePtr; (* $CopyArrays- *)
VAR
port: e.MsgPortPtr;
ioReq: e.IORequestPtr;
BEGIN
port := es.CreatePort("",0);
IF port = NIL THEN RETURN NIL END;
IF ioSize = 0 THEN ioSize := SIZE(e.IOStdReq) END;
ioReq := es.CreateExtIO(port,ioSize);
IF ioReq = NIL THEN es.DeletePort(port); RETURN NIL END;
IF ioInit # NIL THEN ioInit(ioReq) END;
IF e.OpenDevice(name,unit,ioReq,flags) # 0 THEN
es.DeleteExtIO(ioReq);
es.DeletePort(port);
RETURN NIL
END;
RETURN ioReq;
END OpenDev;
PROCEDURE CloseDev (ioReq: e.MessagePtr);
VAR port: e.MsgPortPtr;
BEGIN
port := ioReq.replyPort;
e.CloseDevice(ioReq);
es.DeleteExtIO(ioReq);
es.DeletePort(port);
END CloseDev;
(*---------------------------------------------------------------------*)
PROCEDURE MakeTmpRas (rp: g.RastPortPtr);
VAR tmpRas : g.TmpRasPtr;
buffer : e.ADDRESS;
size : LONGINT;
BEGIN
size := LONG(rp.bitMap.bytesPerRow) * LONG(rp.bitMap.rows);
INCL(ol.MemReqs,e.chip);
ol.New(buffer,size);
EXCL(ol.MemReqs,e.chip);
NEW(tmpRas);
(* rq.Assert((buffer # NIL) & (tmpRas # NIL),oom); macht OberonLib v2.42 *)
g.InitTmpRas(tmpRas^,buffer,size);
rp.tmpRas := tmpRas;
END MakeTmpRas;
PROCEDURE MakeArea (rp: g.RastPortPtr; maxvectors: INTEGER);
VAR areaInfo : g.AreaInfoPtr;
buffer : e.ADDRESS;
BEGIN
ol.New(buffer,maxvectors * 5);
NEW(areaInfo);
g.InitArea(areaInfo^,buffer,maxvectors);
rp.areaInfo := areaInfo;
END MakeArea;
(*---------------------------------------------------------------------*)
PROCEDURE Record;
VAR i,j: INTEGER;
prb: SHORTINT;
audci: SHORTINT;
BEGIN
(* $RangeChk- $OvflChk- $NilChk- *)
audci := hw.aud0i + chan;
(* Audio-Kanal für's Timing benutzen: *)
hw.custom.intena := {audci}; (* Audio-Interrupt sperren *)
hw.custom.aud[chan].ptr := NIL;
hw.custom.aud[chan].len := 1; (* 1 Wort *)
hw.custom.aud[chan].per := 83; (* Sampl.Freq = ca. 21 kHz *)
hw.custom.aud[chan].vol := 0;
hw.custom.dmacon := {hw.aud0+chan}; (* DMA aus *)
e.Disable; (* No interrupts, please *)
hw.custom.intreq := {audci};
hw.custom.aud[chan].dat := 0;
prb := sys.VAL(SHORTINT,hw.ciaa.prb) + sys.VAL(SHORTINT,-128);
(* grrr, blöder Compiler, man muß ihn zwingen, zu glauben,
daß -128 noch SHORTINT ist :-( *)
FOR i := 0 TO n-1 DO
REPEAT UNTIL audci IN hw.custom.intreqr; (* Auf Audio-Interrupt warten *)
hw.custom.intreq := {audci}; (* Interrupt-Bit zurücksetzen *)
hw.custom.aud[chan].dat := 0;
(* Parallel-Port lesen: *)
prb := sys.VAL(SHORTINT,hw.ciaa.prb) + sys.VAL(SHORTINT,-128);
xreal[i] := LONG(prb);
END;
e.Enable;
(* Mit Hammingfunktion gewichten: *)
FOR i := 0 TO n-1 DO
j := (i * (1024 DIV n) + 768) MOD 1024;
xreal[i] := xreal[i] * (sintab[j] DIV 512 + 64);
ximag[i] := 0;
END;
(* $RangeChk= $OvflChk= $NilChk= *)
END Record;
(*---------------------------------------------------------------------*)
PROCEDURE Analyse;
BEGIN
FFT.FFT(xreal,ximag,n); (* Fast-Fourier-Transform aufrufen *)
FFT.Abs(xreal,ximag,9); (* Absolutwerte der komplexen Zahlen berechnen *)
END Analyse;
(*---------------------------------------------------------------------*)
PROCEDURE Muls(x{0},y{1}: INTEGER): LONGINT; (* $EntryExitCode- *)
BEGIN
sys.INLINE(0C1C1H,04E75H);
END Muls;
(*---------------------------------------------------------------------*)
PROCEDURE SetCols;
TYPE
Eq = ARRAY 8 OF INTEGER;
CONST
eq = Eq(64,256,297,341,384,427,469,512); (* Equalizer: Alle Lampen
sollen im Durchschnitt
gleich hell sein *)
VAR
i,c: INTEGER;
s: SET;
BEGIN
FOR i := 0 TO 7 DO
w := 0;
s := sys.VAL(SET,i);
IF s = {} THEN s := {0,2} END;
c := SHORT(ASH(Muls(xreal[i+1],eq[i]),shift));
IF c > 15 THEN c := 15 END;
IF c > hold[i] THEN hold[i] := c
ELSE c := hold[i] END;
IF 0 IN s THEN INC(w,c) END; c := ASH(c,4);
IF 1 IN s THEN INC(w,c) END; c := ASH(c,4);
IF 2 IN s THEN INC(w,c) END;
col[i+4] := w;
DEC(hold[i]);
END;
g.LoadRGB4(vp,col,12);
END SetCols;
(*---------------------------------------------------------------------*)
PROCEDURE MakeMenu(win: I.WindowPtr);
BEGIN
m.StartMenu(win);
m.NewMenu("Projekt");
m.NewItem("Über...","U");
m.NewItem("Ende","E");
m.NewMenu("Kanal");
m.NewItem("Links","L");
m.NewItem("Rechts","R");
m.NewMenu("Pegel");
m.NewItem("Niedrig","1");
m.NewItem("Mittel","2");
m.NewItem("Hoch","3");
menu := m.EndMenu();
IF I.SetMenuStrip(win,menu^) THEN END;
END MakeMenu;
(*---------------------------------------------------------------------*)
PROCEDURE GetIMsg(win: I.WindowPtr; VAR mes: I.IntuiMessage);
VAR msg: I.IntuiMessagePtr;
BEGIN
msg := e.GetMsg(win.userPort);
IF msg # NIL THEN
mes := msg^;
e.ReplyMsg(msg)
ELSE
mes.class := LONGSET{}
END
END GetIMsg;
(*---------------------------------------------------------------------*)
PROCEDURE Flag(s: LONGSET): INTEGER;
VAR i: INTEGER;
BEGIN
IF s = LONGSET{} THEN RETURN 0
ELSE i := -1; REPEAT INC(i) UNTIL i IN s; RETURN i END;
END Flag;
(*---------------------------------------------------------------------*)
PROCEDURE HandleMessage(VAR mes: I.IntuiMessage);
VAR
item: I.MenuItemPtr; itemNum:INTEGER; menuCode: INTEGER;
BEGIN
CASE Flag(mes.class) OF
| 0:
RETURN;
| I.closeWindow:
HALT(0);
| I.menuPick:
menuCode := mes.code;
WHILE menuCode # I.menuNull DO
item := I.ItemAddress(menu^,menuCode);
itemNum := I.ItemNum(menuCode);
CASE I.MenuNum(menuCode) OF
| 0: (* Projekt *)
CASE itemNum OF
| 0: IF rq.RequestWin("Lichtorgel V1.0",
"© 92 by Christian Stiens",
""," Ok ",win) THEN END;
| 1: HALT(0);
ELSE END;
| 1: (* Kanal *)
IF itemNum = 0 THEN
INCL(hw.ciab.pra,1); (* Linken Kanal *)
EXCL(hw.ciab.pra,2); (* selektieren *)
ELSE
EXCL(hw.ciab.pra,1); (* Rechten Kanal *)
INCL(hw.ciab.pra,2); (* selektieren *)
END;
| 2: (* Pegel *)
CASE itemNum OF
| 0: shift := -14
| 1: shift := -13
| 2: shift := -12
ELSE END;
ELSE
END;
menuCode := item.nextSelect;
END;
ELSE
END
END HandleMessage;
(*---------------------------------------------------------------------*)
PROCEDURE IoInit (ioa: e.MessagePtr);
CONST allocMap = "\x01\x02\x04\x08";
BEGIN
WITH ioa: au.IOAudioPtr DO
ioa.data := sys.ADR(allocMap);
ioa.length := 4;
ioa.request.message.node.pri := 127;
END;
END IoInit;
(*---------------------------------------------------------------------*)
BEGIN
IF ver[0]=0X THEN END;
scr := NIL;
win := NIL;
menu := NIL;
ioa := NIL;
pp := -1;
pb := -1;
Misc.base := e.OpenResource(Misc.miscName);
IF Misc.base=NIL THEN HALT(0) END;
pp := Misc.AllocMiscResource(Misc.parallelPort,"Lichtorgel");
pb := Misc.AllocMiscResource(Misc.parallelBits,"Lichtorgel");
rq.Assert((pp=NIL) & (pb=NIL),"Parallel Port belegt");
scr := I.OpenScreen(I.NewScreen(0,0,320,200,
4,
0,1,
{},
I.customScreen,
NIL, NIL, NIL, NIL));
rq.Assert(scr # NIL,"Kein Schirm");
nw := I.NewWindow(0,0, 320, 200,
0,1,
LONGSET{I.menuPick},
LONGSET{I.activate,I.backDrop,I.borderless},
NIL,NIL,
NIL,
NIL,NIL, 0,0,0,0,
I.customScreen);
nw.screen := scr;
win := I.OpenWindow(nw);
rq.Assert(win # NIL,"Kein Fenster");
rp := win.rPort;
vp := I.ViewPortAddress(win);
col[0] := 0;
col[1] := 0CCCH;
col[2] := 000CH;
col[3] := 0C00H;
col[14]:= 0C00H;
col[15]:= 00C0H;
g.LoadRGB4(vp,col,16);
I.ShowTitle(scr,I.LFALSE);
MakeMenu(win);
MakeTmpRas(rp);
MakeArea(rp,4);
FOR i := 0 TO 7 DO
x := i DIV 2 * 77 + 44;
y := i MOD 2 * 88 + 62;
g.SetAPen(rp,i+4);
IF g.AreaCircle(rp,x,y,35) THEN END;
IF g.AreaEnd(rp) THEN END;
END;
ioa := OpenDev(au.audioName,0,LONGSET{},SIZE(au.IOAudio),IoInit);
rq.Assert(ioa # NIL,"Can't open audio.device");
CASE sys.VAL(LONGINT,ioa.request.unit) OF
1: chan := 0 |
2: chan := 1 |
4: chan := 2 |
8: chan := 3 ELSE HALT(0)
END;
hw.ciaa.ddrb := SHORTSET{}; (* Alle Bits Eingang *)
hw.ciab.ddra := hw.ciab.ddra + SHORTSET{1,2}; (* Bit 1 & 2 Output *)
INCL(hw.ciab.pra,1); EXCL(hw.ciab.pra,2); (* Linker Kanal *)
shift := -13; (* Mittlerer Pegel *)
LOOP
GetIMsg(win,mes);
HandleMessage(mes);
Record;
Analyse;
SetCols;
IF e.m68020 IN e.exec.attnFlags THEN
g.WaitTOF END; (* 50 mal/sec reicht :-) *)
END;
CLOSE
IF (pp=NIL)&(pb=NIL) THEN hw.ciab.ddra := hw.ciab.ddra-SHORTSET{1,2} END;
IF ioa # NIL THEN CloseDev(ioa) END;
IF menu# NIL THEN I.ClearMenuStrip(win) END;
IF win # NIL THEN I.CloseWindow(win) END;
IF scr # NIL THEN I.OldCloseScreen(scr) END;
IF pp=NIL THEN Misc.FreeMiscResource(Misc.parallelPort) END;
IF pb=NIL THEN Misc.FreeMiscResource(Misc.parallelBits) END;
END Lichtorgel.